/*
本文件的主要功能： 时间转换与同步
*/
#include "time_sync.h"


/***********************************************************************
对time.h中的结构体解释如下：

struct tm {  
int tm_sec;  秒 – 取值区间为[0,59]   
int tm_min;  分 - 取值区间为[0,59]   
int tm_hour;  时 - 取值区间为[0,23]   
int tm_mday;  一个月中的日期 - 取值区间为[1,31] 
int tm_mon;   月份（从一月开始，0代表一月） - 取值区间为[0,11]   
int tm_year;  年份，其值 + 1900 = 实际年份  
int tm_wday;  星期 – 取值区间为[0,6]，其中0代表星期天，1代表星期一，以此类推  
int tm_yday;  从每年的1月1日开始的天数 – 取值区间为[0,365]，其中0代表1月1日，1代表1月2日，以此类推  
int tm_isdst; 夏令时标识符，实行夏令时的时候，tm_isdst为正。不实行夏令时的进候，tm_isdst为0；不了解情况时，tm_isdst()为负。
};  

struct tm* stctime;

time_t长整型，时间戳: 一般用来表示从1970-01-0100:00:00时以来的秒数
    
**************************************************************************/


struct tm rtctime;  /*RTC 本地时间*/


/*NB的网络时间与 RTC时间同步,一个月一次*/
void APP_TimeSync(void)
{
	time_t stamp;   /*时间戳*/
	char gmttime[26];
	struct tm *gmt; /*GMT时间*/

	BSP_Rtc_ReadDateTime(&rtctime);
	ATClient_Get_GMTtime();
	
    strcpy(gmttime,ATdev.gmttime);

//	printf("Local time : %s\r\n", asctime(&area));	
//	stamp = mktime(&area);
//	stamp += 3600*8;
//	gmt = localtime(&stamp);
//	printf("GMT time: %s\r\n", asctime(gmt));

}


// NB错峰上报,设置下一次定时唤醒时间 0:20
// 每天上报日冻结数据后调用,错峰时间30min内
void APP_Set_Next_WakeUpTime(void)
{
	stc_RTC_Alarm alarm;
	alarm.Hour = ReportTIME_HOUR;
	alarm.Minute = ReportTIME_MIN;
	alarm.Second = ReportTIME_SEC;
	alarm.WeekMask = 0x7F;
	// 产生真随机数
	//< 打开RNG模块时钟门控
	Sysctrl_SetPeripheralGate(SysctrlPeripheralRng, TRUE);
	Trng_Generate();
	Sysctrl_SetPeripheralGate(SysctrlPeripheralRng, FALSE);
	//printf("rng = %x,%x\r\n",Trng_GetData0(),Trng_GetData1());
	uint8_t random = Trng_GetData0()%30;  /*随机数控制在0~30范围内*/
	alarm.Minute += random;
	BSP_Rtc_SetAlarm(&alarm);
}


// +CCLK: "2021/03/20,06:30:20+32"

// NB 获取的时间字符串转通用本地时间结构体
void GMTtimetoLocaltime(char *gmttime, struct tm *localtime)
{




}





/*
*********************************************************************************************************
*    函 数 名: App_CalcWeek
*    功能说明: 根据日期计算星期几
*    形    参: _year _mon _day  年月日  (年是2字节整数，月和日是字节整数）
*    返 回 值: 周几 （0~6） 0表示周日
*********************************************************************************************************
*/
uint8_t APP_CalcWeek(uint16_t _year, uint8_t _mon, uint8_t _day)
{
    /* 
    蔡勒（Zeller）公式 
        历史上的某一天是星期几？未来的某一天是星期几？关于这个问题，有很多计算公式（两个通用计算公式和
    一些分段计算公式），其中最著名的是蔡勒（Zeller）公式。
        即w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 
        
        公式中的符号含义如下，
         w：星期；
         c：年的高2位，即世纪-1
         y：年（两位数）；
         m：月（m大于等于3，小于等于14，即在蔡勒公式中，某年的1、2月要看作上一年的13、14月来计算，
              比如2003年1月1日要看作2002年的13月1日来计算）；
         d：日；
         [ ]代表取整，即只要整数部分。
        
        算出来的W除以7，余数是几就是星期几。如果余数是0，则为星期日。 
        如果结果是负数，负数求余数则需要特殊处理：
            负数不能按习惯的余数的概念求余数，只能按数论中的余数的定义求余。为了方便 
        计算，我们可以给它加上一个7的整数倍，使它变为一个正数，然后再求余数    
        
        以2049年10月1日（100周年国庆）为例，用蔡勒（Zeller）公式进行计算，过程如下： 
        蔡勒（Zeller）公式：w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 
        =49+[49/4]+[20/4]-2×20+[26× (10+1)/10]+1-1 
        =49+[12.25]+5-40+[28.6] 
        =49+12+5-40+28 
        =54 (除以7余5) 
        即2049年10月1日（100周年国庆）是星期5。
    */
    uint8_t y, c, m, d;
    int16_t w;
 
    if (_mon >= 3)
    {
        m = _mon;        
        y = _year % 100;
        c = _year / 100;
        d = _day;
    }
    else    /* 某年的1、2月要看作上一年的13、14月来计算 */
    {
        m = _mon + 12;
        y = (_year - 1) % 100;
        c = (_year - 1) / 100;
        d = _day;
    }
 
    w = y + y / 4 +  c / 4 - 2 * c + ((uint16_t)26*(m+1))/10 + d - 1;    
   
	if (w < 0)    /* 如果w是负数，则计算余数方式不同 */
    {
        w = 7 - (-w) % 7;
    }
    else
    {
        w = w % 7;
    }
    return w;
}



